<?php

class Paging implements Countable, IteratorAggregate
{
	protected $_page = 1;

	protected $_limit = NULL;

	protected $_totalItemCount = NULL;

	protected $_itemCount = NULL;

	protected $_adapter = NULL;

	protected $_offset = NULL;

	protected $_items = NULL;

	protected $_pageCount = NULL;

	private function __construct($adapter, $page, $limit)
	{
		$this -> _adapter = $adapter;
		$this -> setLimit($limit);
		$this -> setPage($page);
	}

	public function factory($data, $page = 1, $limit = NULL)
	{
		if (is_array($data))
		{
			require_once 'paging/adapter/array.php';
			$adapter = new Paging_Adapter_Array($data);
		}
		else
		if ($data instanceof Database_Table_Select)
		{
			require_once 'paging/adapter/tableselect.php';
			$adapter = new Paging_Adapter_Tableselect($data);
		}
		else
		if ($data instanceof Database_Select)
		{
			require_once 'paging/adapter/select.php';
			$adapter = new Paging_Adapter_Select($data);
		}
		else
		if (class_exists('Mongo'))
		{
			// process for mongo selection here.
		}

		return new self($adapter, $page, $limit);
	}

	function setOffset($offset)
	{
		$this -> _offset = intval($offset);
		if ($this -> _offset < 0)
		{
			$this -> _offset = 0;
		}
		return $this;
	}

	function getOffset()
	{
		if (null == $this -> _offset)
		{
			$this -> _offset = 0;
		}
		return $this -> _offset;
	}

	function getLimit()
	{
		if (NULL == $this -> _limit)
		{
			$this -> _limit = 10;
		}
		return $this -> _limit;
	}

	function setLimit($limit)
	{
		$this -> _limit = intval($limit);
		if ($this -> _limit < 1)
		{
			$this -> _limit = 10;
		}
		$this -> _prepareOffset();
		return $this;

	}

	function _prepareOffset()
	{
		$this -> _offset = ($this -> getPage() - 1) * $this -> getLimit();
	}

	function getPage()
	{
		if (NULL == $this -> _page)
		{
			$this -> _page = 1;
		}
		return $this -> _page;
	}

	function setPage($page)
	{
		$this -> _page = intval($page);
		if ($this -> _page < 1)
		{
			$this -> _page = 1;
		}
		$this -> _prepareOffset();
		return $this -> _page;
	}

	function getItems()
	{
		if (NULL === $this -> _items)
		{
			$this -> _items = $this -> _adapter -> getItems($this -> getOffset(), $this -> getLimit());
		}
		return $this -> _items;
	}

	function getTotalItemCount()
	{
		if (NULL === $this -> _totalItemCount)
		{
			$this -> _totalItemCount = $this -> _adapter -> getTotalCount();
		}
		return $this -> _totalItemCount;
	}

	function getItemCount()
	{
		if (NULL == $this -> _itemCount)
		{
			$this -> _itemCount = count($this -> getItems());
		}
	}

	/**
	 * Returns a foreach-compatible iterator.
	 *
	 * @return Traversable
	 */
	function getIterator()
	{
		return $this -> getItems();
	}

	public function count()
	{
		if (NULL == $this -> _pageCount)
		{
			$this -> _pageCount = $this -> getTotalItemCount() / $this -> getLimit();
		}
	}

}
